<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>

</body>
<script>
    //怎么检测数据类型
    //数据类型分为基本数据类型和引用数据类型
    //基本数据类型有 string number boolean null undefined
    //引用数据类型有 object arr {} fn()

    //typeof只对基本数据类型有用引用数据类型不好使比如（[]{})对Array
    var arr = []
    var json = {}
    console.log(typeof arr, typeof json);//输出object

    //检测是否是数组的方法
    var arr = []
    console.log(typeof arr);//typeof对于基本数据类型判断是没有问题的，但是遇到引用数据类型（如对象{},[]）返回的都是object
    console.log(Array.isArray(arr));//输出ture、、Array.isArray()是判断传入的是不是数组

    //检测对象的原型链是否指向构造函数的prototype对象
    console.log(arr instanceof Array);//输出true,instanceof 符运算用于检测构造函数的 prototype 属性是否出现在某个实例对象的原型链上。
    console.log(arr.constructor === Array);//输出true    

    function Fn() { }
    Fn.prototype = new Array()
    var f = new Fn()
    console.log(f.constructor === Fn);//输出false
    console.log(f.constructor === Array);//输出true

    //   基本数据类型的构造函数String,Number,Boolean,Null,Undefined 引用数据类型:Array,Function,Object
    console.log(("1".constructor === String));
    console.log((1).constructor === Number);
    console.log((true).constructor === Boolean);
    //null,undefined 是js设计的一个败笔暂不考虑
    // console.log((null).constructor === Null); 
    // console.log((undefined).constructor === Undefined);
    console.log(([]).constructor === Array);
    console.log((function () { }).constructor === Function);
    console.log(({}).constructor === Object);

    //终极方法从袁兴丽改变对象的指向数组
    var a = Object.prototype.toString//jq源码就用的这个方法进行数据类型检测
    console.log(a.call([]));//检测数组,返回字符串[object Array]检测什么类型传什么的基本类型，返回的是不同'[object 类型]'
    if (a.call([]) === '[object Array]') {
        console.log('true');
    } else {
        console.log('false');
    }

    //什么是原型链?-实例对象(new出的对象)与原型之间的连接关系
    // 一.js的内置对象
    var arr = [1, 2]//字面量
    var arr1 = new Array(1, 2);//实例化,new Array,new的是构造函数 得到的var那个变量叫对象
    //对象下的construction,可得到构造函数
    console.log(arr.constructor);
    console.log(Array);//可查看构造函数的属性
    console.log(Array.prototype);//构造函数原型上是方法
    console.log(arr);//现实中的对象
    console.log(arr.__proto__);//对象都有一个隐式属性 __proto__ ，可以得对象的方法

    //构造函数有显示属性prototype和对象中的__proto__是相等的
    console.log(Array.prototype == arr.__proto__);//输出true

    //js中所有的都是对象-从父级找爷爷
    console.log(Array.prototype.__proto__);
    console.log(Object.prototype);
    console.log(Array.prototype.__proto__ == Object.prototype)//true;

    var obj = {}
    console.log(Array.prototype.__proto__ == obj.__proto__);//true

    //万物皆为空 最终都会找到null
    console.log(Object.prototype.__proto__ == null);//true


    //合并对象,浅拷贝,深拷贝等
    //合并两个对象
    var a = { a: 1, b: 2, d: 5 }
    var b = { a: 2, b: 3, c: 4 }
    // console.log(b['a'],b.a);//对象调用

    //传统的 var in 遍历进行赋值
    for (var key in b) {
        a[key] = b[key]
    }
    console.log(a);//输出Object  {a: 2, b: 3, d: 5, c: 4}

    //检测两个对象是否相等 
    //总体思路-只要两个对象的名和键值都相同。那么两个对象的内容就相同了
    // 1.用Object.keys拿到对象的所有键名数组
    // 2.比对键名数组的长度是否相等。
    // 3.比对键名对应的键值是否相等
    let obj1 = { a: 1, b: [1, 2] }
    let obj2 = { a: 1, b: [2, 3] }

    function compareObj(a, b) {
        var aProps = Object.keys(a);
        var bProps = Object.keys(b)
        console.log(aProps, bProps);//返回对象的键数组
        //比对键数组长度是否相等
        if (aProps.length != bProps.length) {
            return
        }
        //比对键对应的键值是否相等
        for (var i = 0; i < aProps.length; i++) {
            var propName = aProps[i]

            var propA = a[propName]
            var propB = b[propName]

            if (!b.hasOwnProperty(propName)) {
                { return false }
                //判断值是不是对象-如果是,再次递归调用
                if ((propA instanceof Object)) {
                    if (compareObj(propA, propB)) {
                        // return true 这里不能return,后面的对象还没有判断
                    } else {
                        return false
                    }

                }
                else if (propA !== propB) {
                    return false
                }
            }

            return true
        }
    }

    //给对象新增方法，能覆盖掉官方提供的方法
    var arr = [1,2,3,4]
    //es3的方法为
    // arr.push(5)
    // console.log(arr);//[1, 2, 3, 4, 5]
    //内部这样实现-在原型上增加的方法,可以覆盖他已有方法
    Array.prototype.push=function(){
        arr[arr.length]= '6'
        return arr
    }
    console.log(arr.push());// [1, 2, 3, 4, 5, '6']

    Array.prototype.sum = function(){
        var result =0;
        for (var i  = 0;i<this.length;i++)
        {
            result +=this[i]
        }
        return result
    }
    console.log(arr.sum());//106
</script>

</html>